package org.jackysoft.service.impl;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.jackysoft.data.SortInfo;
import org.jackysoft.entity.Folder;
import org.jackysoft.entity.UploadedFileItem;
import org.jackysoft.entity.User;
import org.jackysoft.file.FileSaver;
import org.jackysoft.service.AbstractStringIdServiceImpl;
import org.jackysoft.service.UploadFileService;
import org.jackysoft.util.FileInfo;
import org.jackysoft.util.IOUtils;
import org.jackysoft.util.OperationType;
import org.jackysoft.util.SpringSecurityUtils;
import org.jackysoft.util.StringUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class UploadFileServiceImpl extends
AbstractStringIdServiceImpl<UploadedFileItem> implements
		UploadFileService {

	/**
	 * 
	 */
	private static final long serialVersionUID = -4715102206224915311L;

	public UploadFileServiceImpl() {
		super(UploadedFileItem.class);

	}

	@Override
	public void upload(File[] files, String[] names, String folderId)
			throws DataAccessException {
		User owner = SpringSecurityUtils.getCurrentUser();
		getConfig().checkUserDir(owner.getUsername());
		if (folderId == null)folderId = "myroot";
		for (int i = 0; i < files.length; i++) {
			File file = files[i];
			byte[] data = IOUtils.toByteArray(file);
			upload(data, names[i], folderId);
			
		}

	}

	@Override
	public void upload(byte[] data, String uploadFileName, String folderId)
			throws DataAccessException {
		try {
			User owner = SpringSecurityUtils.getCurrentUser();
			String extName = StringUtils.splitPostFileName(uploadFileName);
			FileInfo f = new FileSaver(data, getConfig(), extName, owner,
					getSession(), folderId, uploadFileName).save();
			log.info(f.getTitle() + "  文件 " + uploadFileName + " 已保存!");
			String opr = " 上传 ";
			OperationType logType = OperationType.User;
			String details = ("用户["+owner.getUsername()+"]"+ owner.getLocalName()+opr+uploadFileName);
			traceLog(logType, opr, details);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	
	@Override
	public List<UploadedFileItem> getByParent(Folder parent, int start, int size)
			throws DataAccessException {
		Session sess = getSession();
		User owner = SpringSecurityUtils.getCurrentUser();
		Criteria crt = sess.createCriteria(UploadedFileItem.class);
		crt.add(Restrictions.eq("folder",
				parent == null ? "myroot" : parent.getId()));
		crt.add(Restrictions.eq("owner", owner));
		crt.addOrder(Order.desc("createTime"));
		crt.setFirstResult(start);
		crt.setMaxResults(size);

		return crt.list();

	}

	@Override
	protected int listDataSize(SortInfo sortInfo, Map<String, Object> smap) {
		String parentId = (String) smap.get("folder");
		Folder parent = new Folder();
		parent.setId(parentId);
		Session sess = getSession();
		User owner = SpringSecurityUtils.getCurrentUser();
		Criteria crt = sess.createCriteria(UploadedFileItem.class);
		crt.setProjection(
				Projections.projectionList().add(Projections.rowCount()))
				.add(Restrictions.eq("folder", parent == null ? "myroot"
						: parent.getId())).add(Restrictions.eq("owner", owner));
		Object o = crt.uniqueResult();
		return o == null ? 0 : Integer.decode(o.toString());
	}

	@Override
	protected List<UploadedFileItem> listData(int start, int size,
			boolean listAll, SortInfo sortInfo, Map<String, Object> smap) {
		String parentId = (String) smap.get("folder");
		Folder parent = new Folder();
		parent.setId(parentId);
		return getByParent(parent, start, size);
	}

	@Override
	protected List<UploadedFileItem> searchData(int start, int size,
			boolean listAll, SortInfo sortInfo, Map<String, Object> smap) {
		String hql = "from " + this.table() + " f ";
		String q = hql + this.getLuceneExpress(smap);
		log.info(q);
		List list = getSession().createQuery(q).list();
		return list;
	}

	@Override
	protected int searchDataSize(SortInfo sortInfo, Map<String, Object> smap) {
		String hql = "select count(*) from " + this.table() + " f ";
		String q = hql + this.getLuceneExpress(smap);
		log.info(q);
		Object o = getSession().createQuery(q).uniqueResult();
		return o == null ? 0 : Integer.parseInt(o.toString());
	}

	@Override
	public String getLuceneExpress(Map<String, Object> smap) {
		Map<String, String> oper = (Map<String, String>) smap.get("operation");
		User owner = SpringSecurityUtils.getCurrentUser();
		String folder = (String) smap.get("folder");
		String where = " where f.folder='" + folder
				+ "' and f.owner.username='" + owner.getUsername() + "' and ";
		for (String field : smap.keySet()) {
			if ("dateStart".equals(field) || "dateEnd".equalsIgnoreCase(field)
					|| "_search".equalsIgnoreCase(field)
					|| "operation".equalsIgnoreCase(field)
					|| "folder".equalsIgnoreCase(field)) {
				continue;
			}

			String[] val = (String[]) smap.get(field);
			if (StringUtils.isBlank(val[0]))
				continue;
			where += "f." + field + " like '%" + val[0] + "%'";
			if (oper.containsKey(field)) {
				String opr = oper.get(field).toString();
				if (!StringUtils.isBlank(opr))
					where += " " + opr + " ";
			}
		}
		if (smap.get("dateStart") != null && smap.get("dateEnd") != null) {
			String startd = ((String[]) smap.get("dateStart"))[0];
			String end = ((String[]) smap.get("dateEnd"))[0];
			if (StringUtils.isNotBlank(startd) && StringUtils.isNotBlank(end)) {
				where += (" f.createTime between '") + (startd) + ("' and '")
						+ (end) + ("' ");

			}
		}

		String q = (where).trim();
		// 211.157.100.109/m/2205
		if (q.endsWith("and")) {
			q = q.substring(0, q.lastIndexOf("and"));
		}
		if (q.endsWith("or")) {
			q = q.substring(0, q.lastIndexOf("or"));
		}
		q += " order by f.createTime desc";
		return q;
	}

}
